package org.wms.minbearwcs.serivce.mission.storageProcessor.booking.Floor3Or4.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.wms.minbearwcs.dao.lift.inf.LiftRequestPointGroupDao;
import org.wms.minbearwcs.dao.stock.inf.MaterialStockDao;
import org.wms.minbearwcs.dao.storage.inf.DualHeadStorageDao;
import org.wms.minbearwcs.dao.storage.inf.DualHeadStorageGroupDao;
import org.wms.minbearwcs.dao.storage.inf.NormalStorageDao;
import org.wms.minbearwcs.entity.DTO.inbound.mission.InboundMissionPoint;
import org.wms.minbearwcs.entity.DTO.transfer.Tuple;
import org.wms.minbearwcs.entity.PO.wcs.storage.dualHeadStorage.DualHeadStorage;
import org.wms.minbearwcs.entity.PO.wcs.storage.dualHeadStorage.DualHeadStorageGroup;
import org.wms.minbearwcs.entity.PO.wcs.storage.dualHeadStorage.type.DualStorageType;
import org.wms.minbearwcs.serivce.mission.storageProcessor.booking.Floor3Or4.Storage3Or4FloorBookingSelector;

import java.lang.ref.ReferenceQueue;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class SortStorage3Or4FloorByProductLine implements Storage3Or4FloorBookingSelector {

    private final MaterialStockDao materialStockDao;
    private final DualHeadStorageGroupDao dualHeadStorageGroupDao;
    private final DualHeadStorageDao dualHeadStorageDao;
    private final NormalStorageDao normalStorageDao;
    private final LiftRequestPointGroupDao liftRequestPointGroupDao;

    @Override
    public synchronized Tuple<InboundMissionPoint> searchAndBooking(String palletCode, String startPoint) {
        String productionLine = materialStockDao.selectProductionLineByPallet(palletCode);
        if (productionLine == null) {
            log.info("无法找到栈板 {} 对应的生产线", palletCode);
            return Tuple.tuple(null, false);
        }

        List<String> dualHeadStorageGroups = dualHeadStorageGroupDao.selectGroupNamesByStorageTypeAndProductionLine(DualStorageType.Floor3Or4DualStorage, productionLine);

        for (String groupName : dualHeadStorageGroups) {
            List<DualHeadStorage> dualHeadStorageList = dualHeadStorageDao.selectByDualHeadStorageGroupCode(groupName);
            Map<Integer, List<DualHeadStorage>> collect = dualHeadStorageList.stream()
                    .collect(Collectors.groupingBy(DualHeadStorage::getRowNum));
            for (List<DualHeadStorage> value : collect.values()) {
                value.sort(Comparator.comparingInt(DualHeadStorage::getColumnNum));
                // TODO : 暂时使用双头双通方案，有需要再加上单头单通
                return findDualEntranceBooking(value, palletCode, startPoint);
            }

        }

        return Tuple.tuple(null, false);
    }


    // 双出口
    private Tuple<InboundMissionPoint> findDualEntranceBooking(List<DualHeadStorage> value, String palletCode, String startPoint) {
        int size = value.size();
        if (size == 0) return Tuple.tuple(null, false);

        int midSize = size / 2 - 1;
        for (int i = midSize; i >= 0; i--) {
            Tuple<InboundMissionPoint> res = dualEntrancejudgeAndBook(value, i, palletCode, startPoint);
            if (res.success) {
                return res;
            }
        }

        for (int i = midSize + 1; i < size; i++) {
            Tuple<InboundMissionPoint> res = dualEntrancejudgeAndBook(value, i, palletCode, startPoint);
            if (res.success) {
                return res;
            }
        }

        return Tuple.tuple(null, false);


    }

    private int statEntrance(DualHeadStorage bookingStorage, int nowNum) {
        if (bookingStorage.getIsEntrance() == 1) {
            return nowNum + 1;
        }
        return nowNum;
    }

    private boolean judgeCanPass(DualHeadStorage bookingStorage) {
        return bookingStorage.getEnable() == 1 &&
                bookingStorage.getBookingPalletCode() == null &&
                bookingStorage.getPalletCode() == null;
    }

    private Tuple<InboundMissionPoint> book(DualHeadStorage dualHeadStorage, String palletCode, String startPoint) {
        dualHeadStorageDao.updateBookingPalletById(dualHeadStorage.getId(), palletCode);
        String liftGroup = normalStorageDao.selectLiftRequestGroupByQrCode(startPoint);
        String requestLiftPoint = liftRequestPointGroupDao.selectRequestPointByGroupCode(liftGroup);
        InboundMissionPoint inboundMissionPoint = new InboundMissionPoint(null,
                dualHeadStorage.getQrPoint(),
                requestLiftPoint);
        return Tuple.tuple(inboundMissionPoint, true);
    }

    private Tuple<InboundMissionPoint> dualEntrancejudgeAndBook(List<DualHeadStorage> value, int i, String palletCode, String startPoint) {
        int size = value.size();
        DualHeadStorage bookingStorage = value.get(i);
        boolean leftJudge = true;
        int leftEntranceNum = 0;
        for (int j = i - 1; j >= 0; j--) {
            DualHeadStorage storage = value.get(j);
            leftEntranceNum = statEntrance(storage, leftEntranceNum);
            boolean canPass = judgeCanPass(storage);
            leftJudge = leftJudge && canPass;
            if (!canPass) {
                break;
            }
        }
        if (leftJudge && leftEntranceNum > 0) {
            return book(bookingStorage, palletCode, startPoint);
        }

        boolean rightJudge = true;
        int rightEntranceNum = 0;
        for (int k = i + 1; k < size; k++) {
            DualHeadStorage storage = value.get(k);
            rightEntranceNum = statEntrance(storage, rightEntranceNum);
            boolean canPass = judgeCanPass(storage);
            rightJudge = rightJudge && canPass;
            if (!canPass) {
                break;
            }
        }

        if (rightJudge && rightEntranceNum > 0) {
            return book(bookingStorage, palletCode, startPoint);
        }

        return Tuple.tuple(null, false);
    }

}
